# -*- coding: utf-8 -*-

 ###############################################
 ##                                             ##
 ##   Submódulo modelo                           ##
 ##   @ Módulo ventas                            ##
 ##                                              ##
 ##   de la línea Básicos                        ##
 ##   de Críptidos Digitales                     ##
 ##   GPL (c)2008                                ##
  ##                                             ##
    ###############################################

# print (0), "  ventas.manejador      begin"

import sys
from decimal import Decimal as dec
from sqlalchemy import desc, or_
# from man import Acepcion, Atributo, Contacto, Direccion, Documento, Entidad, Operacion, PartidaDocumento, Proceso, Producto, Rol
from man import *

import man
from sqlalchemy.sql import func

# print (0), "  ventas.manejador        definitions"


def agrega(data):
    m = "ventas.manejador.agrega()"

    ## Se asume que no hay proceso creado para esta transacción, los pedidos se generan solamente en los servicios y ahi son procesados.

    ## Proceso
    # Se omite fecha y hora para que se capture la actual
    proceso = Proceso(tipo=u'venta', status=u'abierto')
    man.session().add(proceso)
    man.session().flush()

    ## Cliente
    if not data['rol_id']:
        """ Acomoda los datos recibidos de la igu y los registra """
        """ Se apoya en el módulo principal man """
        datosCliente = data.pop('cliente')
        data['rol_id'] = man.rolI(**datosCliente).id

    ## Documento
    documento = Documento(tipo_id=data['tipoDocumento_id'], folio=data['folioDocumento'], fecha=data['fecha'], rol_id=data['rol_id'], subtotal=data['subtotal'], descuento=data['descuento'], impuesto=data['impuesto'], total=data['total'], status=u'cerrado')
    man.session().add(documento)
    man.session().flush()

    costoTotal = dec('0.00')

    for item in data['partidas']:
        costoTotal += item['costo'] * item['cantidad']
        item.update({'documento_id':documento.id})
        item.update({'status':u'cerrada'})

        partida = PartidaDocumento(**item)
        documento.partidas.append(partida)
        man.session().add(partida)

    man.session().flush()

    ## Operacion (se crea despues de calcular el costoTotal)
    operacion = Operacion(cuenta=u'inventarios', tipo=u'salida', fecha=data['fecha'], monto=-costoTotal, status=u'cerrada')
    proceso.operaciones.append(operacion)
    man.session().add(operacion)
    man.session().flush()

    documento.operacion_id = operacion.id
    man.session().add(documento)
    man.session().flush()

    ## PAGO
    if data['pago']:
        if data['pago']['tipo'] == u'efectivo':
            operacionPago = operacionI(cuenta=u'caja', tipo=u'cobro', fecha=data['fecha'], monto=data['total'], status=u'cerrada', proceso=proceso)

            tipoDocumento = atributoI(grupo=u'tipoDocumento', nombre=data['pago']['tipo'])

            documentoPago = Documento(operacion_id=operacionPago.id, tipo_id=tipoDocumento.id, total=data['pago']['total'], subtotal=data['pago']['montoRecibido'], descuento=data['pago']['cambio'], fecha=datetime.datetime.today(), status=u'cerrado')
            man.session().add(documentoPago)
            man.session().flush()

        # formasPago = formasPagoI()

        # tipo = int(data['pago'].split('|').pop(0))

        # if formasPago[tipo].valor==u'efectivo':
            # operacion = Operacion(cuenta=u"caja", tipo=u'cobro', fecha=data['fecha'], monto=data['total'], status=u'cerrada', referencia=data['pago'])
            # proceso.operaciones.append(operacion)
            # man.session().add(operacion)
            # proceso.status = u'cerrado'

        # elif formasPago[tipo].valor==u'cheque':
            # operacion = Operacion(cuenta=u"caja", tipo=u'cobro', fecha=data['fecha'], monto=data['total'], status=u'cerrada', referencia=data['pago'])
            # proceso.operaciones.append(operacion)
            # man.session().add(operacion)
            # proceso.status = u'cerrado'

        # elif formasPago[tipo].valor==u'crédito':
            # operacion = Operacion(cuenta=u"pasivos", tipo=u'cobro', fecha=data['fecha'], monto=data['total'], status=u'cerrada', referencia=data['pago'])
            # proceso.operaciones.append(operacion)
            # man.session().add(operacion)
            # proceso.status = u'abierto'

    consolidaSalidas(documento.partidas)

    modificaFolio(data['folioDocumento'], documento.tipo)

    man.session().commit()

    return documento


def agregaCliente(datos):       # print "ventas.manejador.agregaCliente"
    rol = rol(**datos)

    # entidad = Entidad(datos['personalidad'], datos['nombre'], datos['apellidos'], datos['fechanacimiento'], datos['rfc'], datos['curp'])

    # man.session().add(entidad)
    # man.session().flush()

    # rol = Rol(entidad.id, u'cliente')
    # rol.entidad = entidad

    # man.session().add(rol)
    # man.session().flush()

    # direccion = Direccion(rol.id, u'personal', datos['lugar'], datos['colonia'], datos['codigopostal'], '', datos['calle'])

    # contacto = Contacto(rol.id, u'Tel fijo', datos['telefono'])

    # rol.contactos = [contacto]
    # rol.direcciones = [direccion]

    # man.session().commit()

    return rol


def consolidaSalidas(partidas):
    for partida in partidas:
        producto = productoI(id=partida.producto_id)
        producto.actual -= partida.cantidad
        # if producto.actual:
            # producto.actual -= partida.cantidad
        # else:
            # producto.actual = partida.cantidad
    man.session().flush()


def dameAcepcion(**filtros):
    try:
        if not filtros.has_key('status'):
            filtros['status'] = u'actual'
        registro = man.session().query(Acepcion).filter_by(**filtros).one()
    except:
        print sys.exc_info()
        print filtros

    return registro


def dameAcepciones(**filtros):
    m = "ventas.manejador.dameAcepciones()"
    # print (1), m, filtros

    registros = []
    if filtros.has_key('rol_id'):
        if filtros.has_key('clasificacion'):
            clasificacion = dameClasificacion(valor=filtros['clasificacion'])
            if filtros.has_key('nombre'):
                if filtros.has_key('codigo'):
                    registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).join(Producto).filter(Producto.clasificacion==filtros['clasificacion']).order_by(Acepcion.nombre).all()
                else:
                    registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).join(Producto).filter(Producto.clasificacion==clasificacion).order_by(Acepcion.nombre).all()
            elif filtros.has_key('codigo'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).join(Producto).filter(Producto.clasificacion==filtros['clasificacion']).order_by(Acepcion.codigo).all()
        else:
            if filtros.has_key('nombre'):
                if filtros.has_key('codigo'):
                    registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).order_by(Acepcion.nombre).all()
                else:
                    registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).order_by(Acepcion.nombre).all()
                    # registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(Acepcion.nombre.like("Emp%%")).filter(Acepcion.rol_id==filtros['rol_id']).order_by(Acepcion.nombre).all()
            elif filtros.has_key('codigo'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).filter(Acepcion.rol_id==filtros['rol_id']).order_by(Acepcion.codigo).all()
    else:
        if filtros.has_key('clasificacion'):
            if filtros.has_key('nombre'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).join(Producto).filter(Producto.clasificacion==filtros['clasificacion']).order_by(Acepcion.nombre).all()
            elif filtros.has_key('codigo'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).join(Producto).filter(Producto.clasificacion==filtros['clasificacion']).order_by(Acepcion.codigo).all()
        else:
            if filtros.has_key('nombre'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.nombre).like(("%s%%" % filtros['nombre']).lower())).order_by(Acepcion.nombre).all()
            elif filtros.has_key('codigo'):
                registros = man.session().query(Acepcion).filter(Acepcion.status==u'actual').filter(func.lower(Acepcion.codigo).like(("%s%%" % filtros['codigo']).lower())).order_by(Acepcion.codigo).all()
    return registros


def dameClasificacion(**filtros):
    if 'nombre' in filtros.keys():
        registro = atributoI(grupo=u'clasificacionProducto', valor=filtros['nombre'])
    else:
        registro = atributoI(id=filtros['id'])
    return registro


def clasificaciones():
    registros = atributosI(grupo=u'clasificacionProducto', order=u'valor')
    return registros


def dameCliente(**filtros):
    if 'id' in filtros.keys():
        registro = rol(id=filtros['id'])
    else:
        if filtros.has_key('rfc'):
            registro = man.session().query(Rol).join(Entidad).filter(Entidad.nombre==filtros['nombre']).filter(Entidad.nombre2==filtros['nombre2']).filter(Entidad.rfc==filtros['rfc']).first()
        else:
            registro = man.session().query(Rol).join(Entidad).filter(Entidad.nombre==filtros['nombre']).filter(Entidad.nombre2==filtros['nombre2']).first()
    return registro


# def clienteDefault():
    # clienteDefaultId = int(atributoI(grupo=u'venta', nombre=u'clienteDefault').valor)
    # registro = rol(id=clienteDefaultId)
    # return registro


def dameClientes(**filtros):
    if filtros:
        registros = man.session().query(Rol).join(Entidad).filter(func.lower(Entidad.nombre).like(("%s%%" % filtros['nombre']).lower())).all()
    else:
        registros = man.session().query(Rol).filter(Rol.tipo==u'cliente').all()
    return registros


def condicionesPago():
    registros = atributosI(grupo=u'condicionesPago')
    return registros


def documento(**filtros):
    registro = man.session().query(Documento).filter_by(**filtros).one()
    return registro


def dameFolio(tipoDocumento):
    m = "ventas.manejador.dameFolio()"
    if tipoDocumento.lower() == u'factura':
        folio = int(atributoI(grupo=u'folioDocumento', nombre=u'ventaFiscal').valor)
    elif tipoDocumento.lower() == u'remisión':
        folio = int(atributoI(grupo=u'folioDocumento', nombre=u'ventaControl').valor)
    folio += 1
    return str(folio).zfill(4)


def formasPagoI():
    registros = atributosI(grupo=u'formaPago', order=u'referencia')
    return registros


def dameOperacion(**filtros):
    try:
        if 'cuenta' in filtros.keys():
            registro = man.session().query(Operacion).filter(Operacion.cuenta==filtros['cuenta']).filter(Operacion.documento_id==filtros['documento_id']).one()
        return registro
    except:
        print "Error:", sys.exc_info()[1]
        print "    ventas.manejador.dameOperacion(%s)" % filtros


def dameProceso(**filtros):
    registro = man.session().query(Proceso).filter(Proceso.id==filtros['id']).one()
    return registro


def dameProcesos(**filtros):
    m = "ventas.manejador.dameProcesos()"

    if 'sumasDiarias' in filtros.keys():
        fecha = filtros['inicio']
        totales = []

        while fecha <= filtros['termino']:
            ventas = dameVentasPorFecha(fecha)
            total = dec("0.00")
            for venta in ventas:
                total += venta.total
            totales.append({'fecha':fecha, 'total':total})
            fecha = fecha.addDays(1)
        return totales

    else:
        if 'cliente_id' in filtros.keys():
            registros = man.session().query(Documento).filter(Documento.rol_id==filtros['cliente_id']).filter(Documento.fecha>=filtros['inicio'].toPyDate()).filter(Documento.fecha<=filtros['termino'].toPyDate()).filter(Documento.tipo.in_([u'remisión', u'factura'])).join(Proceso).filter(func.lower(Proceso.tipo).in_([u'venta', u'servicio'])).order_by(Proceso.fecha.asc()).all()
        else:
            registros = man.session().query(Proceso).filter(Proceso.fecha>=filtros['inicio']).filter(Proceso.fecha<filtros['termino']).filter(Proceso.tipo==u'venta').order_by(Proceso.fecha.asc()).all()

            # registros = man.session().query(Documento).filter(Documento.fecha>=filtros['inicio'].toPyDate()).filter(Documento.fecha<=filtros['termino'].toPyDate()).filter(Documento.tipo.in_([u'remisión', u'Factura'])).join(Proceso).filter(func.lower(Proceso.tipo).in_([u'venta', u'servicio'])).order_by(Documento.fecha.desc()).all()

    return registros


#! status es de documento, ¿Para procesos es igual?
    if 'status' in filtros.keys():
        if 'rol_id' in filtros.keys():
            registros = man.session().query(Proceso).filter(Proceso.tipo==filtros['tipo']).filter(Proceso.status==filtros['status']).join(Documento).filter(Documento.rol_id==filtros['rol_id']).order_by(Proceso.fecha).all()
        else:
            registros = man.session().query(Proceso).filter(Proceso.tipo==filtros['tipo']).filter(Proceso.status==filtros['status']).order_by(Proceso.fecha).all()
    else:
        if 'rol_id' in filtros.keys():
            registros = man.session().query(Proceso).filter(Proceso.tipo==u'venta').filter(Proceso.operaciones.any(Operacion.documentos.any(Documento.rol_id==filtros['rol_id']))).order_by(Proceso.fecha).all()
        else:
            registros = man.session().query(Proceso).filter(Proceso.tipo==u'venta').order_by(Proceso.fecha).all()
    return registros


def productoI(**filtros):
    registro = man.session().query(Producto).filter_by(**filtros).one()
    return registro


def rangosPrecio():
    registros = atributosI(grupo=u'rangoPrecioProducto', order=u'referencia')
    return registros


def tipoDocumentoDefault():
    registro = atributoI(grupo=u'tipoDocumentoVenta', nombre=u'default')
    return int(registro.valor)


def tiposDocumento():
    registros = man.session().query(Atributo).filter(Atributo.grupo==u'tipoDocumento').filter(Atributo.referencia.like(u'%venta%')).all()
    return registros


def dameUno(**filtros):
    f=g
    #! obsoleto, use documento()
    registro = man.session().query(Documento).filter(Documento.id==filtros['id']).one()
    return registro


def dameVarios(**filtros):
    return []
    if 'sumasDiarias' in filtros.keys():
        fecha = filtros['inicio']
        totales = []

        while fecha <= filtros['termino']:
            ventas = dameVentasPorFecha(fecha)
            total = dec("0.00")
            for venta in ventas:
                total += venta.total
            totales.append({'fecha':fecha, 'total':total})
            fecha = fecha.addDays(1)
        return totales

    else:
        if 'cliente_id' in filtros.keys():
            registros = man.session().query(Documento).filter(Documento.rol_id==filtros['cliente_id']).filter(Documento.fecha>=filtros['inicio'].toPyDate()).filter(Documento.fecha<=filtros['termino'].toPyDate()).filter(Documento.tipo.in_([u'remisión', u'factura'])).join(Proceso).filter(func.lower(Proceso.tipo).in_([u'venta', u'servicio'])).order_by(Documento.fecha.desc()).all()
        else:
            registros = man.session().query(Documento).filter(Documento.fecha>=filtros['inicio'].toPyDate()).filter(Documento.fecha<=filtros['termino'].toPyDate()).filter(Documento.tipo.in_([u'remisión', u'factura'])).join(Proceso).filter(func.lower(Proceso.tipo).in_([u'venta', u'servicio'])).order_by(Documento.fecha.desc()).all()

    return registros


def dameVentasPorFecha(fecha):
    registros = man.session().query(Documento).join(Proceso).filter(Proceso.tipo==u'venta').filter(Documento.fecha==fecha.toPyDate()).filter(Documento.tipo!=u'pedido').all()
    return registros


def elimina(**filtros):
    registro = man.session().query(Documento).filter(Documento.id==filtros['id']).one()
    man.session().delete(registro)
    man.session().commit()


def modificaFolio(folio, tipoDocumento):
    if tipoDocumento.nombre.lower() == u'remisión':
        registro = atributoI(grupo=u'folioDocumento', nombre=u'ventaControl', valor=unicode(folio))
    elif tipoDocumento.nombre.lower() == u'factura':
        registro = atributoI(grupo=u'folioDocumento', nombre=u'ventaFiscal', valor=unicode(folio))


def totalDeProductos():
    return man.session().query(func.count(Producto.id)).one()[0]-1

def totalDeVentas():
    return man.session().query(func.count(Proceso.id)).filter(Proceso.tipo==u'venta').one()[0]


# print (0), "  ventas.manejador      end"


